package com.senlingspace.payment.event;

import com.alibaba.fastjson2.JSON;
import com.github.rholder.retry.*;
import com.google.common.base.Splitter;
import com.senlingspace.common.core.redis.RedisCache;
import com.senlingspace.common.enums.*;
import com.senlingspace.common.utils.DateUtils;
import com.senlingspace.common.utils.StringUtils;
import com.senlingspace.payment.lakala.bean.response.TradeQueryResponse;
import com.senlingspace.payment.lakala.service.LakalaMicroPayService;
import com.senlingspace.system.domain.SlkjOrder;
import com.senlingspace.system.domain.SlkjOrderStatusCompensation;
import com.senlingspace.system.domain.SlkjOrderStatusLog;
import com.senlingspace.system.mapper.SlkjOrderMapper;
import com.senlingspace.system.mapper.SlkjOrderStatusCompensationMapper;
import com.senlingspace.system.mapper.SlkjOrderStatusLogMapper;
import com.senlingspace.system.mapper.SlkjShoppingCartMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 支付订单状态监听器
 * <p>
 * 仅适用于微信小程序中的支付订单
 *
 * @author lebronjames
 * @date 2024/09/29
 */
@AllArgsConstructor
@Slf4j
@Component
public class PaymentOrderStatusListener {

    private static final String SHOPPING_CART_KEY = "shopping_cart_order_number:";

    private final LakalaMicroPayService lakalaMicroPayService;
    private final SlkjOrderMapper slkjOrderMapper;
    private final SlkjOrderStatusLogMapper slkjOrderStatusLogMapper;
    private final SlkjOrderStatusCompensationMapper slkjOrderStatusCompensationMapper;
    private final SlkjShoppingCartMapper slkjShoppingCartMapper;

    private final RedisCache redisCache;


    /**
     * 微信小程序支付状态监听器
     *
     * @param action
     */
    @Async("threadPoolTaskExecutor")
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onEvent(OrderAction action) {
        log.info("PaymentOrderStatusListener: {}", JSON.toJSONString(action));
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                .retryIfException()
                .retryIfResult(Boolean.FALSE::equals)
                .withWaitStrategy(WaitStrategies.exponentialWait(800, 2, TimeUnit.SECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(5))
                .build();

        // 存储最后一次成功执行的 TradeQueryResponse 对象
        AtomicReference<TradeQueryResponse> lastSuccessfulTradeQuery = new AtomicReference<>();
        // 存储最后一次尝试的结果状态
        final String[] lastTradeState = {null};

        Callable<Boolean> callable = () -> {
            TradeQueryResponse tradeQuery = lakalaMicroPayService.tradeQuery(action.getPaymentRequestId(), action.getShopId());
            lastTradeState[0] = tradeQuery.getRespData().getTradeState();
            if (LakalaTradeStateEnum.fromState(lastTradeState[0]).equals(LakalaTradeStateEnum.SUCCESS)) {
                lastSuccessfulTradeQuery.set(tradeQuery);
                return true;
            }
            return false;
        };

        SlkjOrder order = new SlkjOrder();
        BeanUtils.copyProperties(action, order);
        try {
            // 执行重试机制
            boolean paymentSuccess = retryer.call(callable);
            if (paymentSuccess) {
                log.info("订单 [{}] 支付成功！！！", action.getOrderNumber());
                TradeQueryResponse queryResponse = lastSuccessfulTradeQuery.get();
                if (Objects.nonNull(queryResponse)) {
                    String accSettleAmount = queryResponse.getRespData().getAccSettleAmount();
                    if (StringUtils.isNotEmpty(accSettleAmount)) {
                        accSettleAmount = accSettleAmount.replaceAll("^\"|\"$", "");
                        order.setActualAmount(Integer.parseInt(accSettleAmount));
                    }
                    switch (OrderType.fromCode(order.getOrderType())) {
                        case OT_101:
                            if (order.getSource() == OrderSource.SHOP.getCode()) {
                                order.setBusinessStatus(OrderBusinessStatus.REDEEMED.getCode());
                            } else {
                                order.setBusinessStatus(OrderBusinessStatus.UNREDEEMED.getCode());
                            }
                            break;
                        case OT_102:
                            if (order.getSource() == OrderSource.SHOP.getCode()) {
                                order.setGoodsStatus(GoodsStatusEnum.COMPLETED.name());
                            } else {
                                if (StringUtils.isNotBlank(order.getAddressSnapshot())) {
                                    order.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_SHIPPING.name());
                                } else {
                                    order.setGoodsStatus(GoodsStatusEnum.WAITING_FOR_PICKUP.name());
                                }
                            }
                            break;
                        case OT_103:// 小程序目前不支持混合订单
                            break;
                    }
                    order.setPaymentStatus(LakalaTradeStateEnum.SUCCESS.name());
                    order.setThirdOrderNumber(queryResponse.getRespData().getLogNo());
                    order.setPaymentTime(DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, queryResponse.getRespData().getTradeTime()));
                    order.setUpdateTime(DateUtils.getNowDate());
                    order.setUpdateBy(order.getCreateBy());
                    order.setAccTradeNo(queryResponse.getRespData().getAccTradeNo());

                    log.info("订单 [{}] 支付成功，订单信息为：{}", action.getOrderNumber(), JSON.toJSONString(order));

                    log.info("将订单支付状态改为，支付成功！！！");
                    slkjOrderMapper.updateSlkjOrder(order);

                    log.info("构建订单业务状态变更记录...");
                    SlkjOrderStatusLog statusLog = new SlkjOrderStatusLog();
                    statusLog.setOrderId(order.getOrderId());
                    if (order.getOrderType() == OrderType.OT_102.getCode()) {
                        statusLog.setStatus(order.getGoodsStatus());
                    } else {
                        statusLog.setStatus(order.getBusinessStatus());
                    }
                    statusLog.setChangeBy(Long.valueOf(order.getCreateBy()));
                    statusLog.setChangeTime(DateUtils.getNowDate());
                    log.info("插入订单业务状态变更记录！:{}", JSON.toJSONString(statusLog));
                    slkjOrderStatusLogMapper.insert(statusLog);

                    // 只有商品订单通过购物车支付购买，才会走这个逻辑
                    Object value = redisCache.getCacheObject(SHOPPING_CART_KEY + order.getOrderNumber());
                    if (Objects.nonNull(value)) {
                        log.info("用户支付成功，删除购物车对应数据：{}", value);
                        long[] shoppingCartIds = Splitter.on(",")
                                .trimResults()
                                .omitEmptyStrings()
                                .splitToList(String.valueOf(value)).stream()
                                .mapToLong(Long::parseLong)
                                .toArray();
                        slkjShoppingCartMapper.deleteCart(shoppingCartIds);
                    }
                } else {
                    log.error("拉卡拉支付查询结果为空，数据二次补偿！");
                    statusCompensation(order, new String[]{LakalaTradeStateEnum.DEAL.name()});
                }
            } else {
                log.info("支付状态异常，插入不畅数据！");
                // 支付未成功，插入补偿数据
                statusCompensation(order, lastTradeState);
            }
        } catch (ExecutionException | RetryException | NumberFormatException e) {
            log.error("支付状态异常，插入补偿数据！", e);
            // 捕获异常，插入补偿数据
            statusCompensation(order, lastTradeState);
        }
        log.info("支付订单 [{}] 状态监听器执行完毕！", action.getOrderNumber());
    }

    private void statusCompensation(SlkjOrder order, String[] lastTradeState) {
        SlkjOrderStatusCompensation orderStatusCompensation = new SlkjOrderStatusCompensation();
        orderStatusCompensation.setOrderId(order.getOrderId());
        orderStatusCompensation.setOrderNumber(order.getOrderNumber());
        orderStatusCompensation.setPaymentRequestId(order.getPaymentRequestId());
        orderStatusCompensation.setStatus(lastTradeState[0]);
        orderStatusCompensation.setAttempts(0);
        orderStatusCompensation.setCreateTime(DateUtils.getNowDate());
        orderStatusCompensation.setShopId(order.getShopId());
        log.info("订单 [{}] 支付状态未成功，插入补偿数据！", order.getOrderNumber());
        slkjOrderStatusCompensationMapper.insert(orderStatusCompensation);
    }

}
